-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Don't allow static items to have types with destructors #11979
Conversation
I just realized the tests got lost somewhere. I'll add them right away. |
let tcontents = ty::type_contents(cx.tcx, self_ty); | ||
if tcontents.is_static(cx.tcx) && tcontents.has_dtor() { | ||
cx.tcx.sess.span_err(self_type.span, | ||
"Types with destructors can't be static items"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're trying to have compiler errors start with lowercase letters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't know that, Consider it done!
Why? Process exit will tear down most resources just fine (otherwise the OS is broken), so there is usually no issue in allowing them and simply never running the destructor. For things that aren't torn down by process exit, one could add a new Flush trait that gets called using the C++ global destructor mechanism, but only takes an &mut self, is idempotent and does not destroy the object (so that there are no safety issues related to accessing already destroyed global objects in global object destructors). |
We have been very opposed to "life before main" in terms of static initialization, and we're similarly taking the stance of being opposed to "life after main" in terms of static destruction. For us, once you've made the decision to never run destructors on static variables, we figured it reasonable to just forbid it altogether. |
Can you also add a test for an owned type? Some types I would not want in a static:
Just to make sure that it's not just checking that the type itself has a destructor but rather it requires a destructor in general. |
@alexcrichton done. Tests with |
Hm, "cannot allocate vectors in constant expressions" is a different error than this would be expecting, what happens if you try to make a static of type |
@alexcrichton same error! I think something else is going on there! :/ EDIT: And it's not related to this patch, I'd say. That error is raised also with master. |
This code compiles today, and I just want to make sure that this patch prevents it from compiling: static foo: Option<~str> = None;
fn main() {} |
ItemStatic(self_type, _, _) => { | ||
let self_ty: ty::t = ty::node_id_to_type(cx.tcx, item.id); | ||
let tcontents = ty::type_contents(cx.tcx, self_ty); | ||
if tcontents.is_static(cx.tcx) && tcontents.has_dtor() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per @alexcrichton's comment, I imagine the correct rule here is simply to check that all static things are POD. This would prohibit Option<~T>
, destructors, etc., as well as managed data, which just seems like trouble waiting to happen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might not be good -- it would rule out static atomics, if we want those. I guess the real answer we want is something more like type_needs_drop
but that is a codegen concept, not a language exposed thing (as of yet).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do atomics need a destructor? Can they just be marked with NoPod
now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #12016 (destructor => NoPod
for atomics)
I guess the right thing is just to define a category: "safe for static" or something, which is equivalent to |
Can you add a case for putting |
@nikomatsakis done! thanks! |
Something interesting came up. The summary of the fix for this issue is that static items won't be allowed for types that own The first case, and perhaps the least invasive one, is the The second case is for the static items defined in This last case is an example that suggest enforcing static restrictions on the values as opposed of types as a better solution. After chatting with @nikomatsakis on IRC, it seems that enforcing these rules on the values is not especially hard. There are some cases to consider for I've pushed the latest version of the work. As already mentioned, Thoughts? |
Is this mergeable now, with potentially more conservative rules than we might want later? |
let mutable = match mutability { | ||
ast::MutImmutable => {false} | ||
ast::MutMutable => {true} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not pass around mutability
instead of converting it to a bool? It's self-documenting when you match on it vs having to name it mutable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had an implementation that passed around mutability
, I don't recall why I changed it, TBH. I can change it back
This isn't quite setup how I expect. I expect some code that, at a high-level, works like this:
Note that we do not examine the type of static imm items at all. The necessary restrictions are all implied by checking the initializer expression instead. |
@nikomatsakis thanks for your comment. I now realized that I could've implemented this in other way. I'll revamp this patch. |
@flaper87 ping me when I should re-review |
} else {return None;} | ||
} | ||
_ => {} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems... odd. Structs with destructors are allowed, but enums aren't?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Structs destructors are checked in line L46. The reason we can't use type contents for enums
is that it will also consider the variant constructors types and whether those types have a destructor, which is not good for things like this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds like for immutable statics you want to not use the type contents, but for mutable statics you do indeed want to check the type contents.
With this in mind, can you add a test for this:
enum A { A1(~str), B }
static mut foo: A = B; //~error: `A` has a destructor
ast::ExprCall(..) => { | ||
visit::walk_expr(self, e, is_const); | ||
// We also want to check if the enum | ||
// has a destructor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think tuple struct constructors are also calls, so the comment shouldn't just single out enums
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
ok, I left some comments -- much nicer, almost there but still a bit more refactoring to go I think :) |
- For each *mutable* static item, check that the **type**: - cannot own any value whose type has a dtor - cannot own any values whose type is an owned pointer - For each *immutable* static item, check that the **value**: - does not contain any ~ or box expressions (including ~[1, 2, 3] sort of things) - does not contain a struct literal or call to an enum variant / struct constructor where - the type of the struct/enum has a dtor
This pull request partially addresses the 2 issues listed before. As part of the work required for this PR, `NonCopyable` was completely removed. This PR also replaces the content of `type_is_pod` with `TypeContents::is_pod`, although `type_is_content` is currently not being used anywhere. I kept it for consistency with the other functions that exist in this module. cc #10834 cc #10577 Proposed static restrictions ===================== Taken from [this](#11979 (comment)) comment. I expect some code that, at a high-level, works like this: - For each *mutable* static item, check that the **type**: - cannot own any value whose type has a dtor - cannot own any values whose type is an owned pointer - For each *immutable* static item, check that the **value**: - does not contain any ~ or box expressions (including ~[1, 2, 3] sort of things, for now) - does not contain a struct literal or call to an enum variant / struct constructor where - the type of the struct/enum is freeze - the type of the struct/enum has a dtor
This pull request partially addresses the 2 issues listed before. As part of the work required for this PR, `NonCopyable` was completely removed. This PR also replaces the content of `type_is_pod` with `TypeContents::is_pod`, although `type_is_content` is currently not being used anywhere. I kept it for consistency with the other functions that exist in this module. cc #10834 cc #10577 Proposed static restrictions ===================== Taken from [this](#11979 (comment)) comment. I expect some code that, at a high-level, works like this: - For each *mutable* static item, check that the **type**: - cannot own any value whose type has a dtor - cannot own any values whose type is an owned pointer - For each *immutable* static item, check that the **value**: - does not contain any ~ or box expressions (including ~[1, 2, 3] sort of things, for now) - does not contain a struct literal or call to an enum variant / struct constructor where - the type of the struct/enum is freeze - the type of the struct/enum has a dtor
Does the infrastructure added here make addressing #5244 easier? (Awesome work implementing this, BTW.) |
add configuration for [`wildcard_imports`] to ignore certain imports fixes: rust-lang#11428 changelog: add configuration `ignored-wildcard-imports` for lint [`wildcard_imports`]
This pull request partially addresses the 2 issues listed before. As part of the work required for this PR,
NonCopyable
was completely removed.This PR also replaces the content of
type_is_pod
withTypeContents::is_pod
, althoughtype_is_content
is currently not being used anywhere. I kept it for consistency with the other functions that exist in this module.cc #10834
cc #10577
Proposed static restrictions
Taken from this comment.
I expect some code that, at a high-level, works like this: